#pragma once
#include<iostream>
#include<string>
#include<jsoncpp/json/json.h>
#include"compiler.hpp"
#include"run.hpp"

/***************************
 * 该模块要实现：
 * 1.适配用户请求，定制通信协议字段
 * 2.正确调用compiler和run模块
 * 3.形成唯一的文件名
 *
 * 编译服务可能被多个人请求，必须保证传递上来的code形成源文件名称时要具有唯一性，不能让多个用户之间互相影响
 * 以json串完成用户提供的结构化数据的序列化和反序列化
 * ********************/

namespace ns_compiler_run
{
    using namespace ns_compiler;
    using namespace ns_run;

    class CompilerAndRun
    {
    public:
        CompilerAndRun(){}
        ~CompilerAndRun(){}

        static std::string CodeToDesc(int code,const std::string &file_name)
        {
            std::string desc;
            switch(code)
            {
                case 0:
                desc = "编译运行成功";
                break;
            case -1:
                desc = "提交的代码是空";
                break;
            case -2:
                desc = "未知错误";
                break;
            case -3:
                // desc = "代码编译的时候发生了错误";
                FileUtil::ReadFile(PathUtil::COMPILERERR(file_name), &desc, true);
                break;
            case SIGABRT: // 6
                desc = "内存超过范围";
                break;
            case SIGXCPU: // 24
                desc = "CPU使用超时";
                break;
            case SIGFPE: // 8
                desc = "浮点数溢出";
                break;
            default:
                desc = "未知: " + std::to_string(code);
                break;

            }
            return desc;
        }

        static void RemoveFile(const std::string &file_name)
        {
            sleep(5);
            if(FileUtil::ISFILEEXIT(PathUtil::SRC(file_name))) unlink(PathUtil::SRC(file_name).c_str());
            if(FileUtil::ISFILEEXIT(PathUtil::EXE(file_name))) unlink(PathUtil::EXE(file_name).c_str());
            if(FileUtil::ISFILEEXIT(PathUtil::STDIN(file_name))) unlink(PathUtil::STDIN(file_name).c_str());
            if(FileUtil::ISFILEEXIT(PathUtil::STDOUT(file_name))) unlink(PathUtil::STDOUT(file_name).c_str());
            if(FileUtil::ISFILEEXIT(PathUtil::STDERR(file_name))) unlink(PathUtil::STDERR(file_name).c_str());
            if(FileUtil::ISFILEEXIT(PathUtil::COMPILERERR(file_name))) unlink(PathUtil::COMPILERERR(file_name).c_str());
        }
        /*******************
         * 该函数参数为用户输入的序列化字符串和作为输出结果的反序列化字符串
         * 
         * 输入：
         * code: 用户提供的代码
         * input: 用户代码中的输入
         * cpu_limit: 用户代码的运行时间限制
         * memory_limit: 用户代码的运行内存限制
         * 
         * 输出：
         *  必填：
         *      status:状态码
         *      reason:请求的结果
         *   选填：
         *      stdout:运行完的结果
         *      stderr:运行过程中出现的错误信息
         * 
         * 思路：
         * 1.解析json串，获取用户输入的code、input、cpu_limit、memory_limit
         * 2.生成唯一的文件名，并将用户输入的code写入文件形成源文件
         * 3.调用compiler模块编译源文件，将错误信息写入文件
         * 4.调用run模块运行编译后的可执行文件，并将运行结果写入文件
         * 5.将运行结果和错误信息写入json串，并返回给用户
         * 6.删除中间临时文件
         * *****************/
        static void Start(const std::string &in_json, std::string *out_json)
        {
            //解析json串
            Json::Value in_value;
            Json::Reader reader;
            reader.parse(in_json, in_value);

            std::string code = in_value["code"].asString();
            std::string input = in_value["input"].asString();//输入不做处理
            int cpu_limit = in_value["cpu_limit"].asInt();
            int memory_limit = in_value["mem_limit"].asInt();

            int status_code = 0;    //状态码
            std::string file_name;  //源文件名
            int run_result = 0;     //运行结果
            Json::Value out_value;   //输出json串

            /*******
             * goto语句之间不可以定义变量，否则会导致编译错误
             * *****/
            if(!code.size())
            {
                status_code = -1; 
                goto END;                              //状态码为-1表示代码为空
            }

            //生成唯一的文件名
            //文件名由毫秒级时间戳和自增长id组成,形成的文件名只具有唯一性，没有目录没有后缀
            file_name = FileUtil::UniqueFileName();

            //将用户输入的code写入文件形成源文件
            if(!FileUtil::WriteFile(PathUtil::SRC(file_name),code))
            {
                status_code = -2;                      //状态码为-2表示未知错误
                goto END;
            }
            
            //调用compiler模块编译源文件
            if(!compiler::Compile(file_name))
            {
                status_code = -3;                      //状态码为-3表示编译失败
                goto END;
            }

            //调用run模块运行编译后的可执行文件
            run_result = Run::run(file_name, cpu_limit, memory_limit);
            if(run_result < 0)
            {
                status_code = -4;                      //状态码为-4表示运行失败
                goto END;
            }
            else 
            {
                status_code = run_result;              //状态码为运行结果,0表示运行成功，大于0表示代码被信号终止
                goto END;
            }

            END:
            //将运行结果和错误信息写入json串
            out_value["status"] = status_code;
            out_value["reason"] = CodeToDesc(status_code,file_name);

            if(status_code == 0)
            {
                std::string _stdout;
                FileUtil::ReadFile(PathUtil::STDOUT(file_name),&_stdout,true);
                out_value["stdout"] = _stdout;

                std::string _stderr;
                FileUtil::ReadFile(PathUtil::STDERR(file_name),&_stderr,true);
                out_value["stderr"] = _stderr;
            }

            //下面的写法解决jsoncpp会将中文进行Unicode转义的问题

            // 关键修改：用StreamWriterBuilder替代StyledWriter，关闭中文转义
            Json::StreamWriterBuilder builder;
            builder.settings_["emitUTF8"] = true;  // 确保中文不转义
            builder.settings_["indentation"] = "  ";  // 保持格式化输出
            std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
            std::stringstream ss;
            writer->write(out_value, &ss);
            *out_json = ss.str();  // 赋值给输出JSON字符串

            // Json::StyledWriter writer;
            // *out_json = writer.write(out_value);

            //删除中间临时文件
            RemoveFile(file_name);
        }

    };

}